/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */

package utfpr.cp.model;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.ElementCollection;
import javax.persistence.Entity;
import javax.persistence.EnumType;
import javax.persistence.Enumerated;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToMany;
import javax.persistence.ManyToOne;
import javax.persistence.OneToOne;
import utfpr.cp.crawler.Util;

/**
 *
 * @author Adriano_2
 */
@Entity
public class ResourceData implements Serializable {
    private static final long serialVersionUID = 1L;
    @Id
    @GeneratedValue
    private Long id;
   
    @OneToOne (cascade = CascadeType.PERSIST, fetch = FetchType.EAGER)
    @JoinColumn(unique = true)
    private URLData url;
    
    @Column(columnDefinition="TEXT")
    private String content;
    
    @ManyToMany (cascade = CascadeType.PERSIST)
    private List<URLData> links;
    
    @ElementCollection @Column (length = 1000)
    private final Map<String, String> headers;
    
    @Enumerated(EnumType.ORDINAL)
    private ResourceType type;

    @ManyToOne
    private URLTarget target;
    
    public ResourceData() {
        this.headers = new HashMap<>();
        links = new ArrayList<>();
    }
    
    public ResourceData (URLData url, String content) {
        this();
        this.url = url;
        this.content = content;
        setType(url, content);
    }
    
    public ResourceData (URLData url, String content, List<URLData> links) {
        this.headers = new HashMap<>();
        this.url = url;
        this.content = content;
        this.links = links;
        setType(url, content);
    }
 
    public ResourceData (URLData url, String content, HashSet<URLData> links) {
        this(url, content, new ArrayList<>(links));
    }
    
    public boolean exist() {
        return id != null;
    }
       
    public Long getId() {
        return id;
    }

    @Override
    public String toString() {
        if (exist()) {
            return "utfpr.cp.model.Page[ id=" + getId() + " ]";
        }
        else {
            return "utfpr.cp.model.Page[ " + getUrl().getUrl() + " ] " + links.size() + " links";
        }
    }

    /**
     * @return the url
     */
    public URLData getUrl() {
        return url;
    }

    /**
     * @param url the url to set
     */
    public void setUrl(URLData url) {
        this.url = url;
    }

    /**
     * @return the content
     */
    public String getContent() {
        return content;
    }

    /**
     * @param content the content to set
     */
    public void setContent(String content) {
        this.content = content;
    }

    /**
     * @return the links
     */
    public List<URLData> getLinks() {
        return links;
    }

    /**
     * @param links the links to set
     */
    public void setLinks(List<URLData> links) {
        this.links = links;
    }
    
    public void addHeader(String name, String value) {
        headers.put(Util.maxLength(name, 256), Util.maxLength(value, 1000));
    }
    
    public Map<String, String> getHeaders() {
        return headers;
    }

    /**
     * @return the type
     */
    public ResourceType getType() {
        return type;
    }

    /**
     * @param type the type to set
     */
    public void setType(ResourceType type) {
        this.type = type;
    }

    private void setType(URLData url, String content) {
         if (links.isEmpty()) {
            if (content.trim().length() < 10) {
                this.type = ResourceType.INVALID;
                return ;
            } 
            
            String dataContent = content.trim().substring(0, 10).toLowerCase();
            if (dataContent.startsWith("<!doctype")) {
                //HTML without links
                this.type = ResourceType.HTML;
            }
            else {
                String uri = url.getUrl();
                String ext = uri.substring(uri.length() -4).toLowerCase();
                if (ext.endsWith("js")) {
                    this.type = ResourceType.JAVASCRIPT;
                }
                else if (ext.endsWith("css")) {
                    this.type = ResourceType.CSS;
                }
                else if (ext.endsWith("xml") || dataContent.startsWith("<?xml")) {
                    this.type = ResourceType.XML;
                }
                else {
                    //TODO more tests
                    this.type = ResourceType.PLAIN_TEXT;
                }
            }
        }
        else {
             //TODO test
            this.type = ResourceType.HTML;
        }
    }
    
    /**
     * @return the target
     */
    public URLTarget getTarget() {
        return target;
    }

    /**
     * @param target the target to set
     */
    public void setTarget(URLTarget target) {
        this.target = target;
    }
}
